/*
 *  Copyright (C) 2010 Glauco
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.balisunrise.swing.builder;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.KeyStroke;
import org.balisunrise.annotation.util.ActionUtilities;
import org.balisunrise.annotation.util.AnnotationsUtilitiesException;
import org.balisunrise.application.BaliProperties;
import org.balisunrise.builder.BuilderException;
import org.balisunrise.common.VisualAction;
import org.balisunrise.common.BaliIcons;
import org.balisunrise.common.TransactionActions;

/**
 *
 * @author Glauco
 */
public class BaliActionBuilder 
        implements org.balisunrise.builder.VisualActionBuilder{

    private static final String MESSAGE = "Erro ao construir uma BaliAction.\n";

    public VisualAction create(Object actionMap, ActionUtilities au)
            throws BuilderException {

        if(actionMap == null){
            throw new BuilderException(MESSAGE +
                    "actionMap não pode ser nulo.");
        }

        if(au == null){
            throw new BuilderException(MESSAGE +
                    "ActionUtilities não pode ser nulo.");
        }

        org.balisunrise.swing.transaction.VisualAction action =
                new org.balisunrise.swing.transaction.VisualAction();

        Icon gIcon = BaliIcons.getIcon(au.icon);

        String text = BaliProperties.processText(au.text);

        JButton button = new JButton(text, gIcon);
        
        // verifica focus
        button.setFocusable(au.focusable);

        action.setButton(button);
        action.setMap(actionMap);
        action.setMethod(au.method);
        action.createAction(text, gIcon);

        // nome do botão
        String name = actionMap.getClass().getName() +
                "_action_" + au.alias + "_" + au.method.getName();
        button.setName(name);
        button.getAccessibleContext().setAccessibleName(name);

        if(au.toolTipText != null && au.toolTipText.length() > 0)
            button.setToolTipText(au.toolTipText);

        if(au.accelerator != null && au.accelerator.length() > 0){
            KeyStroke stroke = KeyStroke.getKeyStroke(au.accelerator);
            String mapKey = "handler" + au.accelerator;
            button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(stroke, mapKey);
            button.getActionMap().put(mapKey, action.getAction());
        }

        return action;
    }

    public List<VisualAction> create(Object actionMap, String alias)
            throws BuilderException {

        if(actionMap == null){
            throw new BuilderException(MESSAGE +
                    "actionMap não pode ser nulo.");
        }

        if(alias == null){
            throw new BuilderException(MESSAGE +
                    "alias não pode ser nulo.");
        }

        try{
            
            // lista de utilitarios para criar ações
            List<ActionUtilities> auList =
                    ActionUtilities.createActions(actionMap.getClass(), alias);
            // lista de ações
            List<VisualAction> baList = new ArrayList<VisualAction>();
            // para cada utilitário
            for (ActionUtilities au : auList) {
                // cria nova ação
                baList.add(create(actionMap, au));
            }
            // retorna lista de ações.
            return baList;

        }catch(AnnotationsUtilitiesException aue){

            throw new BuilderException(
                    MESSAGE + aue.getMessage(),
                    aue.getCause());

        }catch(BuilderException be){

            throw be;
        }
    }

    public VisualAction createConfirmationAction(Object actionMap, String alias)
            throws BuilderException {

        VisualAction action = null;

        try {
            ActionUtilities au = ActionUtilities.createConfirmationAction(
                    actionMap.getClass(), alias);
            
            action = create(actionMap, au);

        } catch (Exception e) {
            // Não usar, simplesmente retornar nulo
        }

        // caso não exista a annotação no objeto
        return action;
    }

    public VisualAction createCancellationAction(Object actionMap, String alias)
            throws BuilderException {

        VisualAction action = null;

        try {
            ActionUtilities au = ActionUtilities.createCancellationAction(
                    actionMap.getClass(), alias);

            action = create(actionMap, au);

        } catch (Exception e) {
            // Não usar, simplesmente retornar nulo
        }

        // caso não exista a annotação no objeto
        return action;
    }

    public List<VisualAction> createTransactionAction(
            TransactionActions actionMap)
            throws BuilderException {

        if(actionMap == null){
            throw new BuilderException(MESSAGE +
                    "actionMap não pode ser nulo.");
        }

        //
        List<ActionUtilities> auList = new ArrayList<ActionUtilities>(4);
        //
        List<VisualAction> list = new ArrayList<VisualAction>(4);

        String sIcon = BaliIcons.SEARCH3;
        String nIcon = BaliIcons.NEW3;
        String eIcon = BaliIcons.EDIT3;
        String dIcon = BaliIcons.DELETE3;

        // cria ações
        for (Method method : actionMap.getClass().getMethods()) {
            
            if (method.getName().equals("doSearch")) {

                ActionUtilities au = new ActionUtilities();
                au.actionClass = actionMap.getClass();
                au.alias = "";
                au.icon = sIcon;
                au.index = 0;
                au.method = method;
                au.text = null;
                au.toolTipText = BaliProperties.getString(
                        BaliProperties.searchToolTipText);
                au.accelerator = "F8";
                au.focusable = false;

                auList.add(au);
            }
            if (method.getName().equals("doNew")) {

                ActionUtilities au = new ActionUtilities();
                au.actionClass = actionMap.getClass();
                au.alias = "";
                au.icon = nIcon;
                au.index = 1;
                au.method = method;
                au.text = null;
                au.toolTipText = BaliProperties.getString(
                        BaliProperties.newToolTipText);
                au.accelerator = "F3";
                au.focusable = false;

                auList.add(au);
            }
            if (method.getName().equals("doEdit")) {
                
                ActionUtilities au = new ActionUtilities();
                au.actionClass = actionMap.getClass();
                au.alias = "";
                au.icon = eIcon;
                au.index = 2;
                au.method = method;
                au.text = null;
                au.toolTipText = BaliProperties.getString(
                        BaliProperties.editToolTipText);
                au.accelerator = "F7";
                au.focusable = false;

                auList.add(au);
            }
            if (method.getName().equals("doDelete")) {
                
                ActionUtilities au = new ActionUtilities();
                au.actionClass = actionMap.getClass();
                au.alias = "";
                au.icon = dIcon;
                au.index = 3;
                au.method = method;
                au.text = null;
                au.toolTipText = BaliProperties.getString(
                        BaliProperties.deleteToolTipText);
                au.accelerator = "F6";
                au.focusable = false;
                
                auList.add(au);
            }
        }

        try{
            ActionUtilities.sort(auList);
        }catch (AnnotationsUtilitiesException ex){
            throw new BuilderException(MESSAGE + ex.getMessage());
        }

        for (ActionUtilities au : auList) {
            // cria ação
            VisualAction baliAction = create(actionMap, au);
            // adiciona a lista
            list.add(baliAction);
        }

        return list;
    }
}
